package gc.analyze;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Extract {
	private static final Pattern stopped_pattern = Pattern.compile(".*Total time for which application threads were stopped: (\\d*\\.\\d*) seconds.*");
	private static final Pattern running_pattern = Pattern.compile(".*Application time: (\\d*\\.\\d*) seconds.*");
	private static final Pattern[] patterns = { running_pattern, stopped_pattern };

	public static long[] parse(File file) throws IOException {
		long[] array = new long[0];
		int size = 0;
		try(BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file)))) {
			String line;
			while ((line = reader.readLine()) != null) {
				Matcher matcher;
				matcher = patterns[size & 1].matcher(line);
				if (matcher.matches()) {
					array = append(array, size++, extract(matcher));
				} else {
					matcher = patterns[1 - (size & 1)].matcher(line);
					if (matcher.matches()) {
						System.err.println("!!!:" + line);
						array = append(array, size++, 0);
						array = append(array, size++, extract(matcher));
					}
				}
			}
			if ((size & 1) == 0) {
				array = append(array, size++, 0);
			}
		}
		return trim(array, size);
	}

	static long extract(Matcher matcher) {
		return Math.round(Double.parseDouble(matcher.group(1)) * 1e7);
	}

	static long[] append(long[] array, int pos, long value) {
		if (array.length == pos) {
			int newsize = pos * 2 + 1;
			array = Arrays.copyOf(array, newsize);
		}
		array[pos] = value;
		return array;
	}

	static long[] trim(long[] array, int size) {
		return Arrays.copyOf(array, size);
	}

	public static long[] subsequence(long[] data, long start, long end) {
		int dl = data.length - 1;
		int si = 0;
		long sd = 0;
		while (true) {
			if (si == dl) {
				return new long[] { end - start };
			}
			long td = sd + data[si];
			if (td > start) break;
			sd = td;
			si += 1;
		}
		int ei = si;
		long ed = sd;
		while (ei < dl) {
			long td = ed + data[ei];
			if (td >= end) break;
			ed = td;
			ei += 1;
		}
		int n = ei - si + 1 + (si & 1) + (ei & 1);
		long[] result = new long[n];
		int i = 0;
		if ((si & 1) != 0) {
			result[i++] = 0;
		}
		if (si == ei) {
			result[i++] = end - start;
		} else {
			result[i++] = sd + data[si] - start;
			for (int ii = si + 1; ii < ei; ++ii) {
				result[i++] = data[ii];
			}
			result[i++] = end - ed;
		}
		if ((ei & 1) != 0) {
			result[i++] = 0;
		}
		assert i == result.length : i + " == " + result.length;
		return result;
	}

	static long[] totals(long[] data) {
		long[] totals = new long[3];
		for (int i = 0; i < data.length; ++i) {
			long d = data[i];
			totals[i & 1] += d;
		}
		totals[2] = totals[0] + totals[1];
		return totals;
	}

	static int[] histo_stopped(long[] data, int size, long max) {
		assert size >= 2 : size;
		int n = data.length / 2;
		int[] result = new int[size];
		for (int i = 0; i < n; ++i) {
			long pause = data[2 * i + 1];
			if (pause > max) {
				result[size - 1] += 1;
			} else {
				result[(int) (pause * (size - 1) / max)] += 1;
			}
		}
		return result;
	}

	static void addPoint(double[] coord, int p, double x, double y) {
		coord[2 * p + 0] = x;
		coord[2 * p + 1] = y;
	}
}
